﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Business.Entities;
using GogTasks.Entities;
using Business;
using Business.Logic;
using GogTasks.UserControls;
using System.Threading;
using System.Linq;
namespace GogTasks
{
    public partial class TaskForm : Form
    {
        #region Properties
        private Syncer _syncer;
        private bool _isActive = false;
        private static Font TaskElemFont;
        private MobileOutlookApi _outlook;
        private GoogleApi _google;
        private TasksRoot _root;
        private EditForm _editForm;
        private Task _selectedTask;
        // List of SmoothListBox'es keyed on list name
        private Dictionary<string, SmoothListbox> _listControls;
        // List of page indexes keyed on list name
        private Dictionary<string, int> _listPages;
        private SmoothListbox _currentListControl;
        private bool _isSyncing;
        private bool _isShowingSubForm;
        private SyncProgressControl _syncProgressControl;
        private int _lastScrollPos;
        private string _lastListName;
        private NoListsControl _noListsControl;
        private MoveUserControl _moveControl;
        private bool _isClosing = false;
        public Task SelectedTask { get { return _selectedTask; } }
        /// <summary>
        /// Keeping a list of the paging buttons so that they can be disposed properly
        /// </summary>
        private List<Button> _pagingButtons;


        // TODO: Remember page for each list control

        private delegate void SyncWorkCompleteHandler(Exception ex);

        #endregion

        #region Constructors
        static TaskForm()
        {
            TaskElemFont = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Regular);
        }

        public TaskForm()
        {
            InitializeComponent();
            _pagingButtons = new List<Button>();
            //Trace.Listeners.Add(new TextBoxTraceListener(TraceOutputTextBox));
            GetEditForm();
            this.Menu = null;
        }
        #endregion

        #region Business methods

        private void FetchOutlookTasks()
        {
            _root = _outlook.GetOutlookTasks();
            // Reselect if after sync
            var selectedPre = ListComboBox.SelectedItem;
            if (_currentListControl != null)
            {
                _lastScrollPos = _currentListControl.ScrollPos;
                _lastListName = GetCurrentListName();
            }
            ClearListControls();
            ListComboBox.Items.Clear();
            foreach (var list in _root.lists)
            {
                ListComboBox.Items.Add(list.name == String.Empty? TaskList.DefaultListName: list.name);
            }
            if (selectedPre == null && ListComboBox.Items.Count > 0) ListComboBox.SelectedIndex = 0;
            else if (selectedPre != null) ListComboBox.SelectedItem = selectedPre;
            // renamed can cause zero selection
            if (ListComboBox.SelectedIndex < 0 && ListComboBox.Items.Count > 0) ListComboBox.SelectedIndex = 0;

            // No tasks? Show alternate control
            ShowNoListsControl(ListComboBox.Items.Count == 0);
        }

        private string GetCurrentListName()
        {
            return ListComboBox.SelectedItem as String;
        }

        private TaskList GetCurrentTaskList()
        {
            var selectedList = GetCurrentListName();
            if (selectedList != null)
            {
                return _root.GetListByName(selectedList);
                
            }
            return null;
        }

        private void ShowNoListsControl(bool show)
        {
            if (_noListsControl == null && show)
            {
                _noListsControl = new NoListsControl(SyncMenuItem_Click);
                _noListsControl.Width = Width;
                _noListsControl.Location = new Point(0, 0);
                Controls.Add(_noListsControl);
                _noListsControl.BringToFront();
                _moveControl.BringToFront();
            }
            if (_noListsControl != null)  _noListsControl.Visible = show;
            ListComboBox.Visible = !show;
        }


        private void SetTasksFromActiveList()
        {
            var selectedList = GetCurrentListName();
            if (selectedList != null)
            {
                var taskList = _root.GetListByName(selectedList);
                if (_listControls == null) InitListControls();
                if (_currentListControl != null) Controls.Remove(_currentListControl);
                var listControl = _listControls[taskList.name];
                _currentListControl = listControl;
                Controls.Add(listControl);

                if (selectedList == _lastListName)
                {
                    _currentListControl.ScrollPos = _lastScrollPos; 
                    _lastListName = null;
                }

            }
        }

        private void ClearListControls()
        {
            if (_listControls != null)
            {
                foreach (var list in _listControls.Values)
                {
                    if (list == _currentListControl)
                    {
                        Controls.Remove(list);
                        _currentListControl = null;
                    }
                    list.Dispose();
                }
            }
            _listControls = null;
        }

        private void InitListControl(TaskList taskList)
        {
            // Prepare the control
            var listControl = new SmoothListbox();
            if (_listControls.ContainsKey(taskList.name))
            {
                var lc = _listControls[taskList.name];
                _listControls.Remove(taskList.name);
                //lc.Dispose();
            }
            //Trace.WriteLine("Initing tasklist  [" + taskList.name + "]");
            listControl.ClearControls();
            _listControls.Add(taskList.name, listControl);
            int locY = ListComboBox.Height + ListComboBox.Location.Y + 4;
            listControl.Location = new Point(0, locY);
            int moveControlHeight = 0;
            if (_moveControl != null) moveControlHeight = _moveControl.Height;
            listControl.Size = new Size(Width, Height - locY - moveControlHeight);
            listControl.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
            listControl.DeadZone[0] = 0;
            listControl.DeadZone[1] = 80;
            listControl.BackColor = Color.Black;

            int y = 2;
            var slist = taskList.SortedByOrdinal().child_entity;
            
            // Populate child controls with paging
            CleanupOldPagingButtons(taskList.NameSafe);
            // Prev page button?
            int page = _listPages[taskList.NameSafe];
            if (page > 0)
            {
                var prevCtl = InsertPagingControl(taskList.NameSafe, listControl, false, y);
                y += prevCtl.Height;
            }

            // Task controls
            int tpp = MobileContext.Config.MaxTasksPerPage;
            int start = page * tpp;
            int end = start + tpp;
            if (end > slist.Count) end = slist.Count;
            for (int i = start; i < end; i++)
            {
                Task task = slist[i]; 
                var cb = InsertListControl(listControl, task, y);
                y += cb.Height;
            }

            // Next page button?
            if (end < slist.Count)
            {
                InsertPagingControl(taskList.NameSafe, listControl, true, y);
            }
        }

        private void InitListControls()
        {
            _listControls = new Dictionary<string, SmoothListbox>();
            _listPages = new Dictionary<string, int>();
            CleanupOldPagingButtons(null); 

            foreach (TaskList taskList in _root.lists)
            {
                _listPages[taskList.NameSafe] = 0;
                InitListControl(taskList);
            }
        }

        private CheckTaskControl InsertListControl(SmoothListbox listControl, Task task)
        {
            // Find next Y coordinate
            int y = 0;
            if (listControl.Items.Count > 0)
            {
                var lastItem = listControl.Items[listControl.Items.Count - 1];
                y = lastItem.Location.Y + lastItem.Height;
            }
            // Insert
            return InsertListControl(listControl, task, y);
        }

        private CheckTaskControl InsertListControl(SmoothListbox listControl, Task task, int y)
        {
            var cb = new CheckTaskControl(task);
            cb.Width = Width;
            cb.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
            cb.Font = TaskElemFont;  
            cb.BackColor = Color.Black;
            cb.ForeColor = Color.Wheat;
            cb.CheckBoxAtRight = false;
            cb.CheckBoxAtRight = MobileContext.Config.RightHandedCheckBoxes;
            cb.Location = new Point(2, y);
            cb.Width = listControl.ClientSize.Width;
            cb.Selected += new EventHandler(CheckTaskControl_Selected);
            cb.CheckedChanged += new EventHandler(CheckTaskControl_CheckedChanged);
            cb.SetHeight();
            listControl.AddControl(cb);
            return cb;
        }

        /// <summary>
        /// Insert paging control for selecting previous or next page
        /// </summary>
        /// <param name="next">true if next, false if previous</param>
        /// <returns></returns>
        private Control InsertPagingControl(string listName, SmoothListbox listControl, bool next, int y)
        {
            var panel = new Panel();
            panel.Width = listControl.Width;
            panel.Height =30;
            panel.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
            panel.BackColor = Color.Black;
            panel.ForeColor = Color.Wheat;
            panel.Location = new Point(2, y);
            listControl.AddControl(panel);

            // Create the button
            var button = new Button();
            panel.Controls.Add(button);
            button.Font = TaskElemFont;
            button.Width = listControl.Width - 20;
            
            button.Height = ListComboBox.Height;
            
            button.BackColor = Color.FromArgb(30,30,30);
            button.ForeColor = Color.Gray;
            button.Left = (panel.Width - button.Width) / 2;
            string nextText =  "Next {0} tasks";
            string prevText = "Previous {0} tasks";
            if (next)
            {
                button.Text = String.Format(nextText, MobileContext.Config.MaxTasksPerPage);
                button.Click += PagingNextButton_Click;
            }
            else
            {
                button.Text = String.Format(prevText, MobileContext.Config.MaxTasksPerPage);
                button.Click += PagingPreviousButton_Click;
            }
            button.Tag = listName;
            
            _pagingButtons.Add(button);

            return panel;
        }

        /// <summary>
        /// Disposes no-longer-active paging buttons
        /// </summary>
        /// <param name="listName">Name of list to filter on or null if no filter</param>
        private void CleanupOldPagingButtons(string listName)
        {
            var removeList = new List<Control>();
            foreach (Button button in _pagingButtons)
            {
                // Remove if the button is for the list in question
                if (listName != null && !listName.Equals((string)button.Tag)) continue;
                // One of these will apply
                button.Click -= PagingNextButton_Click;
                button.Click -= PagingPreviousButton_Click;
                button.Dispose();
                removeList.Add(button);
            }
            foreach (Button button in removeList) _pagingButtons.Remove(button);
        }

        private void PagingNextButton_Click(object sender, EventArgs e)
        {
            var taskList = GetCurrentTaskList();
            _listPages[taskList.NameSafe]++;
            InitListControl(taskList);
            SetTasksFromActiveList();
        }

        private void PagingPreviousButton_Click(object sender, EventArgs e)
        {
            var taskList = GetCurrentTaskList();
            _listPages[taskList.NameSafe]--;
            InitListControl(taskList);
            SetTasksFromActiveList();
        }



        private void ShowEditAndDelete()
        {
            _moveControl = new MoveUserControl(this, _outlook);
            _moveControl.SetMenu(OptionsMenuItem);
            _moveControl.EditClicked += EditMenuItem_Click;
            int y = Height - _moveControl.Height;
            int x = (Width - _moveControl.Width) / 2;
            _moveControl.Location = new Point(x, y);
            _moveControl.TasksChanged += new EventHandler(MoveControl_TasksChanged);
            Controls.Add(_moveControl);
            _moveControl.BringToFront();
            if(_currentListControl != null) _currentListControl.Height -= _moveControl.Height;
        }

        private void EnableMenuItems()
        {
            NewTaskMenuItem.Enabled = ListComboBox.Items.Count > 0;
            DeleteTaskMenuItem.Enabled = _selectedTask != null && !_isSyncing;
            //_moveControl.EnableEdit = _selectedTask != null && !_isSyncing;
            _moveControl.EnableEdit = !_isSyncing && ListComboBox.Items.Count > 0;
            _moveControl.SetSelectedTask(_selectedTask);

            //if (!_isSyncing)
            //{
            //    EditMenuItem.Enabled = _selectedTask != null;
            //    DeleteTaskMenuItem.Enabled = _selectedTask != null;
            //    if (_selectedTask != null && _moveControl == null)
            //    {
            //        _moveControl = new MoveUserControl(this, _outlook);
            //        int y = Height - _moveControl.Height;
            //        int x = (Width - _moveControl.Width) / 2;
            //        _moveControl.Location = new Point(x, y);
            //        _moveControl.TasksChanged += new EventHandler(MoveControl_TasksChanged);
            //        Controls.Add(_moveControl);
            //        _moveControl.BringToFront();
            //        _currentListControl.Height -= _moveControl.Height;
            //    }
            //    if (_selectedTask == null && _moveControl != null)
            //    {
            //        Controls.Remove(_moveControl);
            //        _currentListControl.Height += _moveControl.Height;
            //        _moveControl.Dispose();
            //        _moveControl = null;
            //    }
            //    if (_moveControl != null)
            //    {
            //        _moveControl.SetSelectedTask(_selectedTask);
            //        _moveControl.Enabled = _selectedTask != null;

            //        // Resize scrollpane
                    
            //    }
            //}
        }

        private List<CheckTaskControl> GetCheckTaskControls(SmoothListbox listBox)
        {
            int count = listBox.Items.Count;
            var list = new List<CheckTaskControl>(count);
            for (int i = 0; i < count; i++)
            {
                Control c = listBox.Items[i];
                if (c is CheckTaskControl) list.Add((CheckTaskControl) c);
            }
            return list;
        }

        /// <summary>
        /// Sets location with regards to the task ordinal
        /// </summary>
        private void Reposition()
        {
            if (_currentListControl.Items.Count < 1) return;
            int y = GetFirstTaskTop();
           
            // get ordinal-sorted list 
            var tempList = GetCheckTaskControls(_currentListControl);
            var sortedList = tempList.OrderBy(p => p.Task.Ordinal);

            //Trace.WriteLine("--------REPOSITIONING------");
            // iterate
            foreach (CheckTaskControl taskControl in sortedList)
            {
                //Trace.WriteLine("O="+taskControl.Task.Ordinal +", "+ taskControl.Task );
                if (taskControl.Location.Y != y)
                {
                    taskControl.Location = new Point(taskControl.Location.X, y);
                }
                y += taskControl.Height;
            }
            _currentListControl.LayoutItems();
        }

        private int GetFirstTaskTop()
        {
            int topY = Int32.MaxValue;
            foreach (Control c in _currentListControl.Items)
            {
                if (!(c is CheckTaskControl)) continue;
                int thisY = ((CheckTaskControl)c).Top;
                if (thisY < topY) topY = thisY;
            }
            if (topY == Int32.MaxValue) topY = 0;
            return topY;
        }

        ///// <summary>
        ///// Reorders the user controls in the current list with regards to the ordinal of the tasks
        ///// </summary>
        //private void Reorder()
        //{
        //    var list = _root.GetListByName(GetCurrentListName());
        //    var newList = new List<CheckTaskControl>();
        //    foreach (Task task in list.SortedByOrdinal().child_entity)
        //    {
        //        var control = GetControlByTask(task);
        //        newList.Add(control);
        //    }
        //    _currentListControl.ClearControls();
        //    foreach (CheckTaskControl control in newList) _currentListControl.AddControl(control);

        //}

        public override void Refresh()
        {
            Reposition();
            base.Refresh();
        }

        private CheckTaskControl GetControlByTask(Task task)
        {
            if (_currentListControl == null) return null;
            var controls = GetCheckTaskControls(_currentListControl);
            foreach (CheckTaskControl c in controls) if (c.Task == task) return c;
            return null;
        }

        private bool UserIsLoggedIn()
        {
            return _google != null || MobileContext.Config.Cookies != null;
        }

        private void LoginAndSync(bool showProgress)
        {
            if (_isSyncing) return;
            //TraceOutputTextBox.Visible = true;
            if (!UserIsLoggedIn())
            {
                MessageBox.Show("Enter your Google credentials in the settings form in order to synchronize.", "Authentication required");
            }
            else
            {
                _google = new GoogleApi(new JsonApi(), MobileContext.Config.Cookies, MobileContext.Config.GoogleAppsDomainOrNull);
            }
            if (_google != null)
            {
                SynchronizeAsync(showProgress);
            }
            //TraceOutputTextBox.Visible = false;
        }

        private void EnableAll(bool enable)
        {
            EditMenuItem.Enabled = enable;
            OptionsMenuItem.Enabled = enable;
            _moveControl.Enabled = enable;
            CheckTaskControl.DisableAll = !enable;
            if (_noListsControl != null) _noListsControl.Enabled = enable;
            EnableMenuItems();
        }

        private void SetRightOrLeftHanded()
        {
            if (_currentListControl == null) return;
            var controls = GetCheckTaskControls(_currentListControl);
            foreach (CheckTaskControl ct in controls)
                ct.CheckBoxAtRight = MobileContext.Config.RightHandedCheckBoxes;
        }

        private void SetFontSize()
        {
            // Set font size
            if (MobileContext.Config.FontSize == FontSizeEnum.Small)
            {
                ListComboBox.Font = MobileContext.TextFontSmall;
                ListComboBox.Height = (int)(MobileContext.SizeFactor * 40);
            }
            if (MobileContext.Config.FontSize == FontSizeEnum.Medium)
            {
                ListComboBox.Font = MobileContext.TextFontMedium;
                ListComboBox.Height = (int)(MobileContext.SizeFactor * 55);
            }
            if (MobileContext.Config.FontSize == FontSizeEnum.Large)
            {
                ListComboBox.Font = MobileContext.TextFontLarge;
                ListComboBox.Height = (int)(MobileContext.SizeFactor * 70);
            }
        }

        private void SynchronizeAsync(bool showProgress)
        {
            _syncProgressControl = null;
            // Create and showprogress indicator
            if (showProgress)
            {
                _syncProgressControl = new SyncProgressControl();
                _google.ProgressIndicator = _syncProgressControl;
                _syncProgressControl.Location = new Point(0, Height - _syncProgressControl.Height - _moveControl.Height);
                _syncProgressControl.Width = Width;
                _syncProgressControl.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
                Controls.Add(_syncProgressControl);
                _syncProgressControl.BringToFront();
            }

            _isSyncing = true;
            EnableAll(false);
            Thread syncThread = new Thread(Sync_DoWork);
            syncThread.Start();
        }

        private void Sync_DoWork()
        {
            try
            {
                // SynchronizeAsync
                var outlook = new MobileOutlookApi();
                //GoogleApi.UseProxy = true;
                var root = _google.GetAllLists();
                if (_syncProgressControl != null) _syncProgressControl.NextMajorStep();
                var oTaskRoot = outlook.GetOutlookTasks();
                if (_syncProgressControl != null) _syncProgressControl.NextMajorStep();
                _syncer = new Syncer(_google, outlook);
                _syncer.ProgressIndicator = _syncProgressControl;
                _syncer.Sync(root, oTaskRoot);
                if (!IsDisposed) Invoke(new SyncWorkCompleteHandler(Sync_WorkCompleted), new Exception[] { null });
            }

            catch (Exception ex)
            {
                Trace.WriteLine("Google Fetch failed");
                if (!IsDisposed) Invoke(new SyncWorkCompleteHandler(Sync_WorkCompleted), new[] { ex });
            }
        }

        private void Sync_WorkCompleted(Exception ex)
        {
            //if (ex != null && !_loginPerformed)
            //{
            //    //Trace.WriteLine("Attempting relogin");
            //    Trace.WriteLine("Token login failed");
            //    MessageBox.Show("Unable to login. Please re-enter username and password in the settings form");
            //}
            if (ex != null)
            {
                //MessageBox.Show("Error: " + ex.Message, "Synchronization failed");
                ErrorPackage ep = new SyncErrorPackage();
                if (_google != null && _google.ErrorPackage != null) ep = _google.ErrorPackage;
                else if (_syncer != null && _syncer.ErrorPackage != null) ep = _syncer.ErrorPackage;
                else
                {
                    ep.ExceptionMessage = ex.Message;
                    ep.ExceptionStackTrace = ex.StackTrace;
                }
                var ef = new ErrorForm(ep);
                ef.ShowDialog("Error: "+ ex.Message, "Synchronization failed");
            }
            else
            {
                FetchOutlookTasks();
            }
            // remove the progress control
            if (_syncProgressControl != null)
            {
                Controls.Remove(_syncProgressControl);
                _syncProgressControl.Dispose();
                _google.ProgressIndicator = null;
                _syncProgressControl = null;
            }
            _isSyncing = false;
            // Enable
            EnableAll(true);
        }

        private void Edit(Task task)
        {
            //if (_currentListControl == null) CreatEmptyList();
            if (task == null)
            {
                task = new Task();
                task.ListId = _root.GetListByName(GetCurrentListName()).id;
            }

            _isShowingSubForm = true;
            GetEditForm().NewTask(task);
            _isShowingSubForm = false;
        }


        private EditForm GetEditForm()
        {
            if (_editForm == null || _editForm.IsDisposed)
            {
                _editForm = new EditForm();
                _editForm.TaskUpdated += new TaskEventHandler(EditForm_TaskUpdated);
            }
            return _editForm;
        }
        #endregion

        #region Event handlers

        private void TaskForm_Load(object sender, EventArgs e)
        {
            if (Context.JsonApi == null) Context.JsonApi = new JsonApi();
            if (MobileContext.Config == null) MobileContext.Config = Config.Load();
            _outlook = new MobileOutlookApi();
            SetSizeFactor();
            SetFontSize();
            ShowEditAndDelete();
            FetchOutlookTasks();
            EnableAll(true);
            SyncHistory.GetInstance(); // Trigger load
            bool licenseOk = true;
            if (!MobileContext.Config.IsLicenseAccepted)
            {
                var licForm = new LicenseForm();
                var res = licForm.ShowDialog();
                licenseOk = (res == DialogResult.OK);
                if (licenseOk)
                {
                    MobileContext.Config.IsLicenseAccepted = true;
                    MobileContext.Config.Save();
                }
            }
            if (licenseOk)
            {
                ShowWarningsFromOutlookFetch();
                if (MobileContext.Config.AutoSyncOnStart && MobileContext.Config.Cookies != null)
                    LoginAndSync(true);
                if (MobileContext.Config.IsNew) ShowSettings();
            }
            else Close();

            SetBackgroundSyncer();
        }

        private void SetSizeFactor()
        {
            MobileContext.SizeFactor = (float)ListComboBox.Height / 70;
        }

        /// <summary>
        /// Shows any warnings that might have occured during fetching tasks from outlook
        /// </summary>
        private void ShowWarningsFromOutlookFetch()
        {
            if (_outlook == null) return;
            if (_outlook.ErrorLog != null)
            {
                var ep = new ErrorPackage();
                ep.ExceptionMessage = "(Outlook Parse Warnings)";
                ep.ExceptionStackTrace = _outlook.ErrorLog;
                var form = new ErrorForm(ep);
                form.ShowDialog("Some of the data in the local task list was corrupted. This may or may not cause problems upon next synchronization. To help improving this software, you can click Send Error Report below.", "Warning");
                _outlook.ErrorLog = null;
            }
        }

        private bool VerticalMoveBeyondPage(TaskListEventArgs args)
        {
            foreach (Task changedTask in args.ChangedTasks)
            {
                bool found = false;
                foreach (Control control in _currentListControl.Items)
                {
                    if (!(control is CheckTaskControl)) continue;
                    var ctrl = (CheckTaskControl) control;
                    if (ctrl.Task == changedTask)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found) return true;
            }
            return false;
        }

        void MoveControl_TasksChanged(object sender, EventArgs e)
        {
            var te = e as TaskListEventArgs;
            var selTask = _selectedTask;
            //FetchOutlookTasks();
            if (te.ChangeType == ChangeType.MoveVertical)
            {
                // moving beyond page boundaries?
                if (VerticalMoveBeyondPage(te))
                {
                    InitListControl(te.ChangedList); // Full redraw of page
                    SetTasksFromActiveList();
                    DeselectAll();
                    selTask = null;
                }
                else Reposition();
            }
            else
            {
                foreach (Task task in te.ChangedTasks)
                {
                    CheckTaskControl ctrl = GetControlByTask(task);
                    if (ctrl != null)
                    {
                        ctrl.UpdateData();
                        ctrl.Refresh();
                    }
                }
            }
            //SetTasksFromActiveList();
            //------

            _selectedTask = selTask;
            if (_selectedTask != null)
            {
                var controls = GetCheckTaskControls(_currentListControl);
                foreach (CheckTaskControl control in controls)
                {
                    if (control.Task.id == _selectedTask.id) control.IsSelected = true;
                }
            }
            _moveControl.UpdateEnabling();
        }

        void CheckTaskControl_CheckedChanged(object sender, EventArgs e)
        {
            var control = (CheckTaskControl)sender;
            //_outlook.InsertOrUpdateTask(control.Task, null);
            _outlook.UpdateTask(control.Task, null);
            _outlook.Touch(control.Task);
            
        }

        void CheckTaskControl_Selected(object sender, EventArgs e)
        {
            SelectedTaskChanged((CheckTaskControl)sender);
        }

        private void SelectedTaskChanged(CheckTaskControl changed)
        {
            // Deselect all others
            var controls = GetCheckTaskControls(_currentListControl);
            foreach (CheckTaskControl control in controls)
            {
                if (control != changed) control.IsSelected = false;
                else
                {
                    if (control.IsSelected) _selectedTask = control.Task;
                    else _selectedTask = null;
                    EnableMenuItems();
                }
            }
        }

        private void DeselectAll()
        {
            var cts = GetCheckTaskControls(_currentListControl);
            foreach (CheckTaskControl control in cts)
            {
                control.IsSelected = false;
            }
            _selectedTask = null;
            EnableMenuItems();
        }

        private void ListComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Deselect any selected task
            if (_selectedTask != null)
            {
                var changedTask = GetControlByTask(_selectedTask);
                _selectedTask = null;
                if (changedTask != null)
                {
                    changedTask.IsSelected = false;
                    SelectedTaskChanged(changedTask);
                }
            }
            SetTasksFromActiveList();
        }

        private void SyncMenuItem_Click(object sender, EventArgs e)
        {
            LoginAndSync(true);
        }


        private void LogMenuItem_Click(object sender, EventArgs e)
        {
            TraceOutputTextBox.Visible = !TraceOutputTextBox.Visible;
        }

        private void CloseMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }


        private void EditMenuItem_Click(object sender, EventArgs e)
        {
            Edit(_selectedTask);
            //_editForm.EditTask(_selectedTask);
        }

        void EditForm_TaskUpdated(object sender, TaskEventArgs args)
        {
            bool newTask = true;
            var controls = GetCheckTaskControls(_currentListControl);
            foreach (CheckTaskControl c in controls)
            {
                if (c.Task == args.Task)
                {
                    c.UpdateData(); // Updates GUI
                    newTask = false;
                }
            }
            string listName = null;
            if (newTask)
            {
                listName = GetCurrentListName();
                var list = _root.GetListByName(listName);
                list.Add(args.Task);
                args.Task.Ordinal = list.GetMaxOrdinal() + 100; // 100 is just an arbitrary higher number that leaves space 
                var taskControl = InsertListControl(_currentListControl, args.Task);
                taskControl.IsSelected = true;
                SelectedTaskChanged(taskControl);
                _outlook.InsertTask(args.Task, listName);
            }
            else
            {
                _outlook.UpdateTask(args.Task, listName);
            }
            _outlook.Touch(args.Task);
            Reposition();
            _currentListControl.ScrollToBottom();
        }


        private void SettingsMenuItem_Click(object sender, EventArgs e)
        {
            ShowSettings();
        }

        private void ShowSettings()
        {
            bool right = MobileContext.Config.RightHandedCheckBoxes;
            var settings = new SettingsForm();
            _isShowingSubForm = true;
            settings.ShowDialog();
            if (settings.TasksWiped) FetchOutlookTasks();
            else if (right != MobileContext.Config.RightHandedCheckBoxes)
            {
                SetRightOrLeftHanded();
            }
            SetFontSize();
            SetBackgroundSyncer();
            EnableMenuItems();
            _isShowingSubForm = false;
        }

        private void SetBackgroundSyncer()
        {
            if (MobileContext.Config.AutoSyncInBackground)
            {
                Synctimer.Enabled = false;
                Synctimer.Interval = MobileContext.Config.AutoSyncIntervalMinutes * 1000 * 60;
                Synctimer.Enabled = true;
            }
            else
            {
                Synctimer.Enabled = false;
            }

        }

        private void DeleteTaskMenuItem_Click(object sender, EventArgs e)
        {
            TaskList list = _root.GetList(_selectedTask.ListId);
            if (list != null)
            {
                // Delete from _root, Outlook and control list
                var parentTask = _selectedTask.ParentTask;
                int childCount = _selectedTask.Children.Count;
                list.DeleteTask(_selectedTask);
                _outlook.DeleteTask(_selectedTask.OutlookTask);
                if (parentTask != null) _outlook.UpdateTask(parentTask, null);
                _currentListControl.Items.Remove(GetControlByTask(_selectedTask));
                _selectedTask = null;
                // Delete is the only action not leaving any trace in the outlook database with regards to timestamp:
                SyncHistory.GetInstance().OutlookLastModified = DateTime.Now; 
                if (childCount == 0) Reposition();
                else FetchOutlookTasks();
                EnableMenuItems();
            }
        }

        private void NewTaskMenuItem_Click(object sender, EventArgs e)
        {
            Edit(null);
        }

        private void TaskForm_Closed(object sender, EventArgs e)
        {

        }

        private void TaskForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _isClosing = true;
            SyncHistory.GetInstance().Save(); 
        }

        private void TaskForm_Deactivate(object sender, EventArgs e)
        {
            _isActive = false; 
            //System.Diagnostics.Debug.WriteLine("DEAC");
            if (!_isSyncing && !_isClosing && !_isShowingSubForm && 
                MobileContext.Config.AutoSyncOnClose && 
                MobileContext.Config.Cookies != null)
                LoginAndSync(true);
        }

        private void TaskForm_Activated(object sender, EventArgs e)
        {
            _isActive = true;
            if (MobileContext.StartInBackground)
            {
                MobileContext.StartInBackground = false;
                //SendToBack();

                //Minimize();
                HideTimer.Enabled = true;
            }
        }

        private void SyncAndExitMenuItem_Click(object sender, EventArgs e)
        {
            LoginAndSync(true);
            Close();
        }

        private void Synctimer_Tick(object sender, EventArgs e)
        {
            if (!UserIsLoggedIn())
            {
                Trace.WriteLine("BG Sync skipped: User not logged in");
                return;
            }
            if (!_isActive)
            {
                Trace.WriteLine("Background sync triggered at " + DateTime.Now.ToLongTimeString() + " Visible: " + Visible.ToString());
                LoginAndSync(true);
            }
            else
                Trace.WriteLine("Background sync skipped");
        }
        private void HideTimer_Tick(object sender, EventArgs e)
        {
            Minimize();
            HideTimer.Enabled = false;
        }
        #endregion
        [DllImport("coredll.dll")]
        static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

        const int SW_MINIMIZED = 6;

        void Minimize()
        {
            // The Taskbar must be enabled to be able to do a Smart Minimize
            //this.FormBorderStyle = FormBorderStyle.FixedDialog;
            //this.WindowState = FormWindowState.Normal;
            //this.ControlBox = true;
            //this.MinimizeBox = true;
            //this.MaximizeBox = true;

            // Since there is no WindowState.Minimize, we have to P/Invoke ShowWindow
            ShowWindow(this.Handle, SW_MINIMIZED);
        }



    }
}